﻿using System;
using System.Linq;

namespace GT
{
    public static partial class Extensions
    {
        public static DateTime AddWorkdays(this DateTime d, int days)
        {
            // start from a weekday
            while (d.DayOfWeek.IsWeekday()) d = d.AddDays(1.0);
            for (int i = 0; i < days; ++i)
            {
                d = d.AddDays(1.0);
                while (d.DayOfWeek.IsWeekday()) d = d.AddDays(1.0);
            }
            return d;
        }

        public static DateTime GetClosestDayOfWeek(this DateTime d, DayOfWeek day)
        {
            if (d.DayOfWeek == day)
                return d;

            int forward = 0;
            int reverse = 0;

            for (int i = 1; i < 7; i++)
            {
                if (d.AddDays(i).DayOfWeek == day)
                {
                    forward = i;
                    break;
                }
            }

            for (int i = 1; i < 7; i++)
            {
                if (d.AddDays(-(i)).DayOfWeek == day)
                {
                    reverse = i;
                    break;
                }
            }

            if (forward < reverse)
                return d.AddDays(forward);
            else
                return d.AddDays(-(reverse));

        }

        public static DateTime GetNextDayOfWeek(this DateTime d, DayOfWeek day, bool inclusive = true)
        {
            if (inclusive && d.DayOfWeek == day)
                return d;

            DateTime ret = d;
            while (ret.DayOfWeek != day)
            {
                ret = ret.AddDays(1);
            }
            return ret;
        }

        public static DateTime GetNextDayOfWeek(this DateTime d, DayOfWeek[] days, bool inclusive = true)
        {
            if (inclusive && days.Any(i => i == d.DayOfWeek))
                return d;

            DateTime ret = d;
            while (!days.Any(i => i == ret.DayOfWeek))
            {
                ret = ret.AddDays(1);
            }
            return ret;
        }

        public static DateTime GetPreviousDayOfWeek(this DateTime d, DayOfWeek day, bool inclusive = true)
        {
            if (inclusive && d.DayOfWeek == day)
                return d;

            DateTime ret = d;
            while (ret.DayOfWeek != day)
            {
                ret = ret.AddDays(-1);
            }
            return ret;
        }

        public static DateTime GetPreviousDayOfWeek(this DateTime d, DayOfWeek[] days, bool inclusive = true)
        {
            if (inclusive && days.Any(i => i == d.DayOfWeek))
                return d;

            DateTime ret = d;
            while (!days.Any(i => i == ret.DayOfWeek))
            {
                ret = ret.AddDays(-1);
            }
            return ret;
        }

        public static bool IsBetween(this DateTime d, DateTime startDate, DateTime endDate)
        {
            return (d >= startDate && d <= endDate);
        }

        public static bool IsWeekday(this DayOfWeek d)
        {
            switch (d)
            {
                case DayOfWeek.Sunday:
                case DayOfWeek.Saturday: return false;

                default: return true;
            }
        }

        public static bool IsWeekend(this DayOfWeek d)
        {
            return !d.IsWeekday();
        }

        public static TimeSpan TimeElapsed(this DateTime date)
        {
            return DateTime.Now - date;
        }

        public static string ToRFC822DateString(this DateTime date)
        {
            int offset = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now).Hours;
            string timeZone = "+" + offset.ToString().PadLeft(2, '0');
            if (offset < 0)
            {
                int i = offset * -1;
                timeZone = "-" + i.ToString().PadLeft(2, '0');
            }
            return date.ToString("ddd, dd MMM yyyy HH:mm:ss " + timeZone.PadRight(5, '0'), System.Globalization.CultureInfo.GetCultureInfo("en-US"));
        }
    }
}
